// SPDX-License-Identifier: GPL-2.0
#include <linux/module.h>
#include <linux/netfilter.h>
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_alg_debug.h>

#define DBG_BUF_LEN 256

void (*alg_debug_hook)(const char *proto, const char *pstr_fmt, ...);
EXPORT_SYMBOL(alg_debug_hook);

void (*alg_debug_exp_hook)(const char *proto, const char *exp_type,
			   struct nf_conn *ct, struct nf_conntrack_expect *exp);
EXPORT_SYMBOL(alg_debug_exp_hook);

void (*alg_debug_result_hook)(const char *proto, const char *msg_type, uint32_t result);
EXPORT_SYMBOL(alg_debug_result_hook);

void (*alg_debug_recvpkg_hook)(const char *proto, const char *msg_type,
			       struct nf_conn *ct, enum ip_conntrack_info ctinfo);
EXPORT_SYMBOL(alg_debug_recvpkg_hook);

void (*alg_debug_mangle_data_hook)(const char *proto, const char *ptr, uint32_t len,
				   const char *key, bool flag);
EXPORT_SYMBOL(alg_debug_mangle_data_hook);

void (*alg_debug_mangle_addr_port_hook)(const char *proto, uint16_t l3num,
					union nf_inet_addr *addr, uint16_t port,
					const char *key, bool flag);
EXPORT_SYMBOL(alg_debug_mangle_addr_port_hook);

void alg_debug(const char *proto, const char *fmt, ...)
{
	va_list args;
	char buf[DBG_BUF_LEN] = {0};
	typeof(alg_debug_hook) dfn;

	va_start(args, fmt);
	vsnprintf(buf, sizeof(buf) - 1, fmt, args);
	va_end(args);

	dfn = rcu_dereference(alg_debug_hook);
	if (!dfn)
		return;

	dfn(proto, "%s", buf);
}
EXPORT_SYMBOL(alg_debug);

inline void alg_debug_exp(const char *proto, const char *exp_type,
			  struct nf_conn *ct, struct nf_conntrack_expect *exp)
{
	typeof(alg_debug_exp_hook) dfn;

	dfn = rcu_dereference(alg_debug_exp_hook);
	if (!dfn)
		return;

	dfn(proto, exp_type, ct, exp);
}
EXPORT_SYMBOL(alg_debug_exp);

inline void alg_debug_result(const char *proto, const char *msg_type, uint32_t result)
{
	typeof(alg_debug_result_hook) dfn;

	dfn = rcu_dereference(alg_debug_result_hook);
	if (!dfn)
		return;

	dfn(proto, msg_type, result);
}
EXPORT_SYMBOL(alg_debug_result);

inline void alg_debug_recvpkg(const char *proto, const char *msg_type,
			      struct nf_conn *ct, enum ip_conntrack_info ctinfo)
{
	typeof(alg_debug_recvpkg_hook) dfn;

	dfn = rcu_dereference(alg_debug_recvpkg_hook);
	if (!dfn)
		return;

	dfn(proto, msg_type, ct, ctinfo);
}
EXPORT_SYMBOL(alg_debug_recvpkg);

inline void alg_debug_mangle_data(const char *proto, const char *ptr, uint32_t len,
				  const char *key, bool flag)
{
	typeof(alg_debug_mangle_data_hook) dfn;

	dfn = rcu_dereference(alg_debug_mangle_data_hook);
	if (!dfn)
		return;

	dfn(proto, ptr, len, key, flag);
}
EXPORT_SYMBOL(alg_debug_mangle_data);

inline void alg_debug_mangle_addr_port(const char *proto, uint16_t l3num,
				       union nf_inet_addr *addr, uint16_t port,
				       const char *key, bool flag)
{
	typeof(alg_debug_mangle_addr_port_hook) dfn;

	dfn = rcu_dereference(alg_debug_mangle_addr_port_hook);
	if (!dfn)
		return;

	dfn(proto, l3num, addr, port, key, flag);
}
EXPORT_SYMBOL(alg_debug_mangle_addr_port);

